﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using RestSharp;
using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace JenkinsCodeBuid.Service
{
    public class BuildCodeHelper
    {
        private static string MD5(string source)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] bytes = Encoding.UTF8.GetBytes(source);
            string result = BitConverter.ToString(md5.ComputeHash(bytes));
            return result.Replace("-", "");
        }
        public async static Task BuildReleaseSite(string site, IConfiguration configuration,string baseUrl)
        {
            await Task.Run(async() => {
                //if (!CommonConst.AllWebSite.Any(q => q == site))
                //{
                //    return;
                //}

                var projectName = "WebApi";
                var projectPath = site;
                if (site.EndsWith("App"))
                {
                    projectPath = site.ReplaceLast("App", "");
                    projectName = "AppApi";
                    if(site.Contains("HysEC.Customers"))
                    {
                        projectName = "ClientWebApi";
                    }
                    //var path = $@"C:\Program Files (x86)\Jenkins\workspace\hysyun.hyyx\{projectPath}\{projectPath}.{projectName}";
                }
                var path = @$"{CommonConst.JenkinsUrl}\{projectPath}\{projectPath}.{projectName}";

                var outPath = configuration.GetSection("OutPath").Value;
                outPath = $@"{outPath}\{site}";
                Log.Error($"编译输出路径{outPath}");
                string cmdTxt = $@"
cd {path}
dotnet publish {projectPath}.{projectName}.csproj --configuration release  --framework netcoreapp2.2 --runtime win-x64 --output {outPath}";
                Log.Error($"编译文本{cmdTxt}");
                CommonConst.Msg.AppendLine("开始编译");
                string strOut = ExeCommand(cmdTxt, true);
                if(strOut.Contains(": error"))
                {
                    throw new Exception("编译失败"+strOut);
                }
                CommonConst.Msg.AppendLine("编译完成");
                Log.Error($"编译结果{strOut}");
                //CommonConst.Msg.AppendLine(outPath);


                ////删除指定文件夹下的文件
                //var fileName = $@"C:\WebSite\{site}\appsettings.Development.json";
                //File.Delete(fileName);
                //fileName = $@"C:\WebSite\{site}\appsettings.json";
                //File.Delete(fileName);
                //fileName = $@"C:\WebSite\{site}\web.config";
                //File.Delete(fileName);
                ////添加压缩包
                //string filname = site + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".zip";
                //var zippathfile = outPath + @"\" +filname;
                //ZipFileCompression.ZipFile(outPath, zippathfile);
                ////调用文件上传工具
                //var url = "http://47.100.37.13:28070/Home/Upload";

                //FileStream fs = new FileStream(zippathfile, FileMode.Open, FileAccess.Read);
                //byte[] buffur = new byte[fs.Length];
                //fs.Read(buffur, 0, (int)fs.Length);
                //RestClientHelper.PostImport(url, buffur, filname);
                ////删除压缩包
                //File.Delete(zippathfile);
                if (strOut.Contains("项目文件不存在"))
                {
                    throw new Exception("项目文件不存在-路劲错误");
                }
                if(!strOut.Contains("正在确定要还原的项目"))
                {
                    throw new Exception("没有权限或者配置编辑目录不正确");
                }
                Log.Error($"停止站点");
                var str= RestClientHelper.PostData<string>($"{baseUrl}:28070/Home/StopSite",new { website =site}).Result;
                CommonConst.Msg.AppendLine(str);
                var uploadUrl = configuration.GetSection("UploadUrl").Value;
                Log.Error($"上传文件路径{uploadUrl}");
                //获取指定目录下所有文件和子目录文件名称
                //string[] filenames = Directory.GetFileSystemEntries(outPath);

                DirectoryInfo dir = new DirectoryInfo(outPath);
                var files = dir.GetFiles();

                var tasks = new Dictionary<string, Task<string>>();
                var index = 0;
                var uploadCount = 0;
                var fileCount = 0;
                var key = false ? MD5($"{site}{DateTime.Now.ToString("yyyyMMdd")}") : "";
                Log.Error($"开始上传文件");
                foreach (var file in files)
                {
                    var fileName = Path.GetFileName(file.FullName);
                    if (fileName.Contains("appsettings") && fileName.Contains(".json"))
                    {
                        continue;
                    }
                    if (fileName.Contains(".config"))
                    {
                        continue;
                    }

                    //LogData("准备上传文件" + fileName, site);
                    tasks.Add(fileName, PostData(uploadUrl, new { website = site, key, index = index++, clearAllFiles = 0, autoUncompress = 0 }, fileName, file.FullName));
                    fileCount++;
                    if (index % 30 == 0)
                    {
                        var t = tasks.Select(x => x.Value).ToList();
                        var result = await Task.WhenAll(t);
                        result.ForEach(x => {
                            //CommonConst.Msg.AppendLine($"{x}");
                            if (!string.IsNullOrEmpty(x) && x.Contains("成功"))
                            {
                                uploadCount++;
                            }
                        });
                        CommonConst.Count = uploadCount;
                        tasks = null;
                        tasks = new Dictionary<string, Task<string>>();
                    }
                }
                //上传余下的
                foreach (var task in tasks.Keys)
                {
                    var temp = await tasks[task];
                    if (!string.IsNullOrEmpty(temp) && temp.Contains("成功"))
                    {
                        uploadCount++;
                    }
                    CommonConst.Count = uploadCount;
                }
                Log.Error($"上传文件完成");
                //var  newfilenames = filenames.Where(x => !(x.Contains("appsettings") || x.Contains("appsettings.Development") || x.Contains("web.config"))).ToList();

                //int i = 0;
                //foreach (var file in newfilenames)
                //{
                //    using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
                //    {
                //        MultipartFormDataContent content = new MultipartFormDataContent();
                //        //打开文件
                //        FileStream fs = File.OpenRead(file);
                //        content.Add(new StreamContent(fs), "file",file);

                //        //还可以添加键值对参数,web api 可以通过 request.Form["id"] 接收
                //        content.Add(new StringContent(i.ToString()), "index");
                //        content.Add(new StringContent("0"), "clearAllFiles");
                //        content.Add(new StringContent("0"), "autoUncompress");
                //        content.Add(new StringContent(site), "webSite");

                //        var result = client.PostAsync(uploadUrl, content).Result;
                //        str = result.Content.ReadAsStringAsync().Result;
                //    }
                //}
                Log.Error($"启动站点");
                str = RestClientHelper.PostData<string>($"{baseUrl}:28070/Home/StartSite", new { website = site, key}).Result;
                CommonConst.Msg.AppendLine(str);
                Log.Error($"启动站点成功");
            });
        }

        public async static Task UploadReleaseSite(string site, IConfiguration configuration,string baseUrl)
        {
            await Task.Run(async () => {

                var path = configuration.GetSection("OnLineSetting:LoacalFileAddress").Value;

                path = $@"{path}/{site}";

                Log.Error($"上传文件路径{path}");

                var key = true ? MD5($"{site}{DateTime.Now.ToString("yyyyMMdd")}") : "";
                Log.Error($@"停止站点");
                var str = RestClientHelper.PostData<string>($"{baseUrl}:28070/Home/StopSite", new { website = site,key= key }).Result;
                CommonConst.Msg.AppendLine(str);

                DirectoryInfo dir = new DirectoryInfo(path);
                var files = dir.GetFiles();
                var tasks = new Dictionary<string, Task<string>>();
                var index = 0;
                var uploadCount = 0;
                var fileCount = 0;

                Log.Error($"开始上传文件");
                foreach (var file in files)
                {
                    var fileName = Path.GetFileName(file.FullName);
                    if (fileName.Contains("appsettings") && fileName.Contains(".json"))
                    {
                        continue;
                    }
                    if (fileName.Contains(".config"))
                    {
                        continue;
                    }

                    //LogData("准备上传文件" + fileName, site);
                    tasks.Add(fileName, PostData(CommonConst.UploadSite, new { website = site, key, index = index++, clearAllFiles = 0, autoUncompress = 0 }, fileName, file.FullName));
                    fileCount++;
                    if (index % 30 == 0)
                    {
                        var t = tasks.Select(x =>x.Value).ToList();
                        var result = await Task.WhenAll(t);
                        result.ForEach(x => {
                            //CommonConst.Msg.AppendLine($"{x}");
                            if (!string.IsNullOrEmpty(x) && x.Contains("成功"))
                            {
                                uploadCount++;
                            }
                            CommonConst.Count = uploadCount;
                        });
                        //每隔maxPerUploadFileCount上传一次
                        //foreach (var task in tasks.Keys)
                        //{
                        //    var temp = await tasks[task];
                        //    CommonConst.Msg = $"{site}--{file}--{temp}";
                        //    if (!string.IsNullOrEmpty(temp) && temp.Contains("成功"))
                        //    {
                        //        uploadCount++;
                        //    }
                        //}
                        tasks = null;
                        tasks = new Dictionary<string, Task<string>>();
                    }
                }
                //上传余下的
                foreach (var task in tasks.Keys)
                {
                    var temp = await tasks[task];
                    if (!string.IsNullOrEmpty(temp) && temp.Contains("成功"))
                    {
                        uploadCount++;
                    }
                    //CommonConst.Msg.AppendLine($"{task}{temp}");
                    CommonConst.Count = uploadCount;
                }
                Log.Error($"上传文件完成");
                Log.Error($"启动站点");
                str = RestClientHelper.PostData<string>($"{baseUrl}:28070/Home/StartSite", new { website = site, key = key }).Result;

                CommonConst.Msg.AppendLine(str);
                Log.Error($"启动站点成功");
            });
        }

        /// <summary>
        /// Post数据
        /// </summary>
        /// <param name="postUrl"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        private static async Task<string> PostData(string postUrl, object entity, string fileName = "", string filePath = "")
        {
            try
            {
                var client = new RestClient() { BaseUrl = new Uri(postUrl) };
                client.DefaultParameters.Clear();
                IRestRequest request;
                var site = "";

                if (!string.IsNullOrEmpty(fileName) && !string.IsNullOrEmpty(filePath))
                {
                    request = new RestRequest(Method.POST);
                    request.AddFile("file", filePath);
                    foreach (var p in entity.GetType().GetProperties())
                    {
                        if (p.Name == "website") { site = (string)p.GetValue(entity); }
                        request.AddParameter(p.Name, p.GetValue(entity));
                    }
                }
                else
                {
                    request = new RestRequest(postUrl, Method.POST, DataFormat.Json);
                    request.AddParameter("Accept", "application/json, text/javascript, */*; q=0.01", ParameterType.HttpHeader);
                    request.AddParameter("Content-Type", "application/json", ParameterType.HttpHeader);
                    request = request.AddJsonBody(entity);
                }
                var response = await client.ExecuteTaskAsync(request);
                var content = response.StatusCode == HttpStatusCode.OK ? response.Content : $"请求失败：{response.StatusCode}";
                return fileName+content;
            }
            catch (Exception e)
            {
                return "请求异常：" + e.Message;
            }
        }
        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="commandText"></param>
        /// <param name="needOutPut"></param>
        /// <returns></returns>
        private static string ExeCommand(string commandText, bool needOutPut = false)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            string strOutput = null;
            try
            {
                p.Start();
                p.StandardInput.WriteLine(commandText);
                p.StandardInput.WriteLine("exit");
                strOutput = p.StandardOutput.ReadToEnd();
                if (!strOutput.Contains("ERROR") && !needOutPut)
                {
                    strOutput = "";
                }
                p.WaitForExit();

                p.Close();
            }
            catch (Exception e)
            {
                strOutput = e.Message;
            }
            return strOutput;
        }
    }
}
